package com.tinygray.lock;

import lombok.SneakyThrows;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @Author: tinygray
 * @Description: 公众号:Madison龙少，关注我你会越来越优秀。
 * @className: RWLock
 * @create: 2021-05-08 18:20
 */
public class RWLock {

    public static void main(String[] args) {
        //资源类 ：缓存
//        MyCacheNoRWLock myCache = new MyCacheNoRWLock();
        //资源类 ：缓存
        MyCacheRWLock myCacheRWLock = new MyCacheRWLock();

        //线程操作资源类:写入操作
        for (int i = 0; i <5 ; i++) {
            final int tempNumber = i;
            new Thread(() -> {
//                myCache.put(tempNumber + "", tempNumber + "");
                myCacheRWLock.put(tempNumber + "", tempNumber + "");
            }, String.valueOf(i)).start();
        }
        //线程操作资源类 ：读取操作
        for (int i = 0; i <5 ; i++) {
            final int tempNumber = i;
            new Thread(() -> {
//                myCache.get(tempNumber + "");
                myCacheRWLock.get(tempNumber + "");
            }, String.valueOf(i)).start();
        }

    }
}

/**
 * 手写一个简单的缓存（缓存其实底层就是hashmap）
 *  未加锁版本
 *   缓存一般都用volatile修饰map
 */
class MyCacheNoRWLock {
    /**
     * 缓存中的东西，必须保持可见性，因此使用volatile修饰
     */
    private volatile Map<String, Object> map = new HashMap<>();

    @SneakyThrows
    public void put(String key, Object value) {
        System.out.println(Thread.currentThread().getName() + "\t 正在写入：" + key);
        Thread.currentThread().join(100);
        map.put(key, value);
        System.out.println(Thread.currentThread().getName() + "\t 写入完成");
    }

    @SneakyThrows
    public void get(String key) {
        System.out.println(Thread.currentThread().getName() + "\t 正在读取：" + key);
        Thread.currentThread().join(300);
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName() + "\t 读取完成：" + o);
    }

    public void clear(){
        map.clear();
    }
}

/**
 * 手写一个简单的缓存（缓存其实底层就是hashmap）
 *  加锁版本
 *  保证
 */
class MyCacheRWLock {
    /**
     * 缓存中的东西，必须保持可见性，因此使用volatile修饰
     */
    private volatile Map<String, Object> map = new HashMap<>();
    private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
    /**
     * 定义写操作
     * 满足：原子 + 独占
     * @param key
     * @param value
     */
    @SneakyThrows
    public void put(String key, Object value) {
        reentrantReadWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "\t 正在写入：" + key);
            // 模拟网络拥堵，延迟0.3秒
            Thread.currentThread().join(300);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "\t 写入完成");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantReadWriteLock.writeLock().unlock();
        }
    }
    @SneakyThrows
    public void get(String key) {
        reentrantReadWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "\t 正在读取：" + key);
            // 模拟网络拥堵，延迟0.3秒
            Thread.currentThread().join(300);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName() + "\t 读取完成：" + o);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            reentrantReadWriteLock.readLock().unlock();
        }
    }

    public void clear(){
        map.clear();
    }
}